package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.constants.MQConstants;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.exception.LyException;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.dto.SpuDetailDTO;
import com.leyou.item.entity.*;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {
    @Autowired
    BrandService brandService;
    @Autowired
    CategoryService categoryService;
    @Autowired
    SpuDetailService spuDetailService;
    @Autowired
    SkuService skuService;
    @Autowired
    AmqpTemplate amqpTemplate;

    @Override
    public PageDTO<SpuDTO> querySpuByPage(Integer page, Integer rows, Integer bid, Integer cid, Integer id, Boolean saleable) {
        //1.考虑健壮性
        int current = Math.max(page, 1);
        int size = Math.max(rows, 5);
        //2.构造查询条件 --chain 链式 ，wrapper
        //QueryWrapper<T> 与 Page<T>应该是同一种类型
        QueryWrapper<Spu> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq(bid!=null,"brand_id",bid)
                .eq(cid!=null,"cid3",cid)
                .eq(id!=null,"id",id)
                .eq(saleable!=null,"saleable",saleable);

        Page<Spu> result = page(new Page<>(current, size), queryWrapper);
        //3.解析查询结果
        long total = result.getTotal();
        long pages = result.getPages();
        List<Spu> list = result.getRecords();
        //4.po - DTO
        List<SpuDTO> spuDTOList = SpuDTO.convertEntityList(list);
        for (SpuDTO spuDTO : spuDTOList) {
            //查询spu的分类和品牌的名称
            handleCategoryAndBrandName(spuDTO);
        }
        //5.返回分页结果
        return new PageDTO<>(total, pages, spuDTOList);
    }

    /**
     *
     * @param spuDTO
     */
    @Override
    @Transactional
    public void saveGoods(SpuDTO spuDTO) {
        //1.DTO - PO 保存spu
        Spu spu = spuDTO.toEntity(Spu.class);
        spu.setSaleable(false);
        boolean saveSuccess = save(spu);    //参考老师 ，优化
        if (!saveSuccess) {
            throw new LyException("新增商品失败", 500);
        }
        //2.SpuDTO 取 spuDetail 然后保存
        SpuDetail spuDetail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);
        spuDetail.setSpuId(spu.getId());
        boolean success = spuDetailService.save(spuDetail);
        if (!success) {
            throw new LyException("新增商品详情失败", 500);
        }
        //3.SpuDTO 取 skus 遍历，然后保存
        List<SkuDTO> skuDTOlist = spuDTO.getSkus();
        List<Sku> Skulist = skuDTOlist.stream()
                .map(skuDTO -> {
                    Sku sku = skuDTO.toEntity(Sku.class);
                    sku.setSaleable(false);
                    sku.setSpuId(spu.getId());
                    return sku;
                })
                .collect(Collectors.toList());
        //批量新增
        skuService.saveBatch(Skulist);
    }

    /**
     * 修改商品
     * @param spuDTO
     */
    @Override
    @Transactional  //todo 需要重新考虑
    public void updateGoods(SpuDTO spuDTO) {
        //1.修改spu
        // 1.1.判断是否存在spu的id，有说明需要修改，没有说明不需要
        Long spuid = spuDTO.getId();
        if (spuid!=null){
            Spu spu = spuDTO.toEntity(Spu.class);
            boolean updateSuccess = updateById(spu);
            if (!updateSuccess) {
                throw new LyException("更新商品失败", 500);
            }
        }
        //2.0更新Spudetail
        //考虑健壮性，查询后，判断为否为空，在执行别的操作
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();
        //2.0判断Detail为null？
        if (spuDetailDTO!=null && spuDetailDTO.getSpuId()!=null) {
            SpuDetail spuDetail = spuDetailDTO.toEntity(SpuDetail.class);
            boolean success = spuDetailService.updateById(spuDetail);
            if (!success) {
                throw new LyException("更新商品失败", 500);
            }

        }
        /**
         * 3 修改sku 另一种方案
         */
        /*List<SkuDTO> skuDTOlist = spuDTO.getSkus();
        List<Sku> SkuList = skuDTOlist.stream()
                .map(skuDTO -> {
                    Sku sku = skuDTO.toEntity(Sku.class);
                    sku.setSaleable(true);
                    sku.setSpuId(spuDTO.getId());
                    return sku;
                })
                .collect(Collectors.toList());
        for (Sku sku : SkuList) {
            boolean updateSku = skuService.updateById(sku);
            if (!updateSku) {
                throw new LyException("更新Sku失败", 500);
            }
        }*/
        //3 修改sku
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        //3.1.判断是否包含sku
        if (CollectionUtils.isEmpty(skuDTOList)) {
            return;
        }
        //3.2装换DTO并将sku根据saleable是否为null来分组。null，是新增或修改，不是null是删除
        Map<Object, List<Sku>> map = skuDTOList.stream()
                .map(skuDTO -> skuDTO.toEntity(Sku.class))
                .collect(Collectors.groupingBy(sku -> sku.getSaleable() == null));
        //3.3 获取要新增或修改的sku
        List<Sku> skus = map.get(true);
        // 如果不为空，则修改或新增
        if(!CollectionUtils.isEmpty(skus)) {
            skuService.saveOrUpdateBatch(skus);
        }
        //3.4 获取要删除的sku
        List<Sku> deleteSkus = map.get(false);
        if(!CollectionUtils.isEmpty(deleteSkus)){
            // 存在要删除的sku
            List<Long> idList = deleteSkus.stream()
                    .map(Sku::getId)
                    .collect(Collectors.toList());
            // 删除
            skuService.removeByIds(idList);
        }

    }

    /**
     * 商品上下架
     * @param id
     * @param saleable
     */
    @Override
    @Transactional
    public void updateSaleable(Long id, Boolean saleable) {
        //1.更新spu
        Spu spu = new Spu();
        spu.setSaleable(saleable);
        spu.setId(id);
        boolean successSpu = updateById(spu);//可以优化，失败异常处理
        if (!successSpu) {
            throw new LyException("更新失败", 500);
        }
        //2.更新sku
        boolean successSku = skuService.update().eq("spu_id", id).set("saleable", saleable).update();
        if (!successSku) {
            throw new LyException("Sku更新失败", 500);
        }
        //3.发送MQ消息
        String routingKey = saleable ? MQConstants.RoutingKeyConstants.ITEM_UP_KEY : MQConstants.RoutingKeyConstants.ITEM_DOWN_KEY;
        amqpTemplate.convertAndSend(MQConstants.ExchangeConstants.ITEM_EXCHANGE_NAME,routingKey,id);
    }

    /**
     *  根据spuId商品id 查询SPU,SKU,SKUDetail
     * @param spuId
     * @return
     */
    @Override
    public SpuDTO querySpuSpuDSkuById(Long spuId) {
        //1 po - dto
        Spu spu = getById(spuId);
        SpuDTO spuDTO = new SpuDTO(spu);
        //2. po - detail
        SpuDetail spuDetail = spuDetailService.getById(spu.getId());
        SpuDetailDTO spuDetailDTO = new SpuDetailDTO(spuDetail);
        spuDTO.setSpuDetail(spuDetailDTO);
        //3.spuId -- list<Sku>
        List<Sku> skuList = skuService.query().eq("spu_id", spu.getId()).list();
        List<SkuDTO> skuDTOList = SkuDTO.convertEntityList(skuList);
        spuDTO.setSkus(skuDTOList);
        return spuDTO;
    }

    /**
     * 根据spuId 查询所有的规格参数值 主表查询SpecParam ,SpecParam服务实现
     * @param spuId
     * @param searching
     * @return
     */

    /**
     * 查询spu的分类和品牌的名称 --构造方法
     */
    private void handleCategoryAndBrandName(SpuDTO spuDTO) {
        //根据品牌id查询品牌名称
        Brand brand = brandService.getById(spuDTO.getBrandId());
        if (brand !=null) {
            spuDTO.setBrandName(brand.getName());
        }
        //根据三级分类id查询分类集合
        List<Category> categories = categoryService.listByIds(spuDTO.getCategoryIds());
        if (!CollectionUtils.isEmpty(categories)) {
            //取出分类的名称，拼接起来
            String names = categories.stream()
                    .map(Category::getName)
                    .collect(Collectors.joining("/"));
            System.out.println(names);
            spuDTO.setCategoryName(names);
        }
    }
}
